﻿#region Usings

using System.Windows;
using Box2DX.Common;

#endregion

namespace SilverBox.Physics
{
    public class SimulatorContext
    {
        private Vector2 screenBottomRight;
        private Vector2 screenTopLeft;
        private Vector2 worldBottomRight;
        private Vector2 worldTopLeft;

        public SimulatorContext(Vector2 screenTopLeft, Vector2 screenBottomRight, Vector2 worldTopLeft,
                                Vector2 worldBottomRight)
        {
            this.screenTopLeft = screenTopLeft;
            this.screenBottomRight = screenBottomRight;
            this.worldTopLeft = worldTopLeft;
            this.worldBottomRight = worldBottomRight;
        }

        private float ScreenWidth
        {
            get { return (screenBottomRight - screenTopLeft).X; }
        }

        private float ScreenHeight
        {
            get { return (screenBottomRight - screenTopLeft).Y; }
        }

        public Vector2 ScreenToWorld(Point screen)
        {
            return ConvertCoordinates((float) screen.X, (float) screen.Y, screenTopLeft, screenBottomRight, worldTopLeft,
                                      worldBottomRight, true);
        }

        public Point WorldToScreen(Vector2 world)
        {
            Vector2 value = ConvertCoordinates(world.X, world.Y, worldTopLeft, worldBottomRight, screenTopLeft,
                                               screenBottomRight, true);

            return new Point(value.X, value.Y);
        }

        public Vector2 ScreenSizeToWorldSize(Size size)
        {
            return ConvertSize(new Vector2((float) size.Width, (float) size.Height), screenTopLeft, screenBottomRight,
                               worldTopLeft, worldBottomRight, true);
        }

        public Vector2 ScreenSizeToWorldSize(Point size)
        {
            return ConvertSize(new Vector2((float) size.X, (float) size.Y), screenTopLeft, screenBottomRight,
                               worldTopLeft, worldBottomRight, true);
        }

        public Size WorldSizeToScreenSize(Vector2 size)
        {
            Vector2 result = ConvertSize(size, worldTopLeft, worldBottomRight, screenTopLeft, screenBottomRight, true);
            return new Size(result.X, result.Y);
        }

        private Vector2 ConvertCoordinates(float x, float y, Vector2 topLeft1, Vector2 bottomRight1, Vector2 topLeft2,
                                           Vector2 bottomRight2, bool invertY)
        {
            float w1 = bottomRight1.X - topLeft1.X;
            float h1 = bottomRight1.Y - topLeft1.Y;
            float u = (x - topLeft1.X)/w1;
            float v = (y - topLeft1.Y)/h1;
            if (invertY)
            {
                v = 1 - v;
            }
            var p = new Vector2();
            p.X = ((1.0f - u)*topLeft2.X) + (u*bottomRight2.X);
            p.Y = ((1.0f - v)*topLeft2.Y) + (v*bottomRight2.Y);
            return p;
        }

        private Vector2 ConvertSize(Vector2 size, Vector2 topLeft1, Vector2 bottomRight1, Vector2 topLeft2,
                                    Vector2 bottomRight2, bool invertY)
        {
            float w1 = bottomRight1.X - topLeft1.X;
            float h1 = bottomRight1.Y - topLeft1.Y;
            float w2 = bottomRight2.X - topLeft2.X;
            float h2 = bottomRight2.Y - topLeft2.Y;
            float rw = (w2/w1);
            float rh = (invertY ? -1 : 1)*(h2/h1);
            var p = new Vector2();
            p.X = size.X*rw;
            p.Y = size.Y*rh;
            return p;
        }
    }
}